
// Copyright (C) 2010-2011 Luca Piccioni
// 
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//   
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;

using Derm.Xml;

namespace Derm.Render
{
	/// <summary>
	/// Interface used for allocating and releasing graphic resources.
	/// </summary>
	/// <remarks>
	/// <para>
	/// This interface defines a common interface for those objects which are allocated on an OpenGL context. These
	/// objects belongs to one of the following classes:
	/// - Display list (actually not supported)
	/// - Textures object (<see cref="Derm.Render.Texture"/>)
	/// - Buffer object (<see cref="BufferObject"/>)
	/// - Shader object (<see cref="ShaderObject"/>)
	/// - Shader program (<see cref="Derm.Render.ShaderProgram"/>)
	/// - Shader program pipeline (actually not supported)
	/// - Render buffer object (<see cref="Derm.Render.RenderBuffer"/>)
	/// - Framebuffer object (<see cref="Derm.Render.RenderFramebuffer"/>)
	/// - Query object (actually not supported)
	/// - Sync object (actually not supported)
	/// - Transform feedback object (actually not supported)
	/// </para>
	/// <para>
	/// These object classes can be shared between different <see cref="RenderContext"/> instances, constructed in the proper way. Actually current
	/// OpenGL specification are not officially supporting all those object classes, but in the real world it actually works thanks to drivers
	/// implementations.
	/// </para>
	/// <para>
	/// The IRenderResource exposes methods and properties which enable the interface user to identify the object by a name (<see cref="ObjectName"/>). It
	/// also enable the interface user to check effectively the IRenderResource existence (<see cref="Exists"/>).
	/// </para>
	/// <para>
	/// The IRenderResource defines methods used for allocating and releasing object resources (<see cref="Create"/>, <see cref="Delete"/>.
	/// The methods <see cref="Create"/> and <see cref="Delete"/> are context dependent, since the object creation and
	/// deletion is dependent on the current context of the executing thread.
	/// </para>
	/// <para>
	/// The object deletion (using <see cref="Delete"/> requires a current context on the calling thread. This cannot be always true, because design
	/// limitation (i.e. IRenderResource inherit IDisposable) or because application design (i.e. multithreading); but if the IRenderResource
	/// is not deleted by <see cref="Delete"/>, it causes a resource leak on an OpenGL context.
	/// 
	/// To avoid the resource leaks, it was introduced the <see cref="RenderGarbageService"/>, which is a garbage collector of IRenderResource instances.
	/// Pratically, a IRenderResource can be deleted in successive stages by collecting it in the only <see cref="RenderGarbageService"/> instance, and
	/// later request to delete all objects belonging to a <see cref="RenderContext"/>.
	/// 
	/// Here it comes the <see cref="Release"/> method. This method have the same functionality of <see cref="Delete"/>, but without requiring a current
	/// context. Ideally, a tipical implementation of this method would garbage the IRenderResource instance (by interacting with
	/// <see cref="RenderGarbageService"/>). However, it is necessary to schedule the object delection by using <see cref="RenderGarbageService.DeleteGarbage"/>.
	/// </para>
	/// <para>
	/// The IRenderResource interface inherits from <see cref="System.IDisposable"/>. The IDisposable implementation is used to ensure object resources
	/// by means of the <i>using</i> construct. Tipically <see cref="System.IDisposable.Dispose"/> implementation shall call <see cref="Release"/>,
	/// since it cannot be sure what (and if a) <see cref="RenderContext"/> is current on the calling thread.
	/// </para>
	/// <para>
	/// A direct implementation of this interface is the <see cref="Derm.Render.RenderResource"/> class, which it can be inherited. This class implements most of
	/// IRenderResource interface, leaving to the inheritor a few ones to overrides. This is the suggested way to implement the IRenderResource interface,
	/// but there can be some special cases which is necessary the interface inherition; in the case implements the interface following the interface
	/// guidelines.
	/// </para>
	/// </remarks>
	/// <seealso cref="Derm.Render.RenderResource"/>
	/// <see cref="RenderGarbageService"/>
	public interface IRenderResource : IXmlSerializableExt, IReferenced, IDisposable
	{
		#region Resource Identification

		/// <summary>
		/// Resource identifier.
		/// </summary>
		/// <remarks>
		/// This string is used to identify this IRenderResource among a collection. This identifier has to be
		/// unique in order to be collected by <see cref="RenderResourceDb"/>.
		/// </remarks>
		string Identifier { get; }

		/// <summary>
		/// Object class.
		/// </summary>
		/// <remarks>
		/// <para>
		/// The object class identify the resource type. It cannot be <see cref="System.Guid.Empty"/>, but a meaninfull
		/// value. The allowed values are determine in the concrete implementation of the IRenderResource
		/// implementation.
		/// </para>
		/// </remarks>
		Guid ObjectClass { get; }

		/// <summary>
		/// Object name used for this IRenderResource.
		/// </summary>
		uint ObjectName { get; }

		/// <summary>
		/// Determine whether this IRenderResource really exists for a specific context.
		/// </summary>
		/// <param name="ctx">
		/// A <see cref="RenderContext"/> that would have created (or a sharing one) the object. This context shall be current to
		/// the calling thread.
		/// </param>
		/// <returns>
		/// It returns a boolean value indicating whether this object exists in the object space of <paramref name="ctx"/>.
		/// </returns>
		/// <remarks>
		/// <para>
		/// The object existence is done by checking a valid object by its name <see cref="ObjectName"/>. This routine will test whether
		/// <paramref name="ctx"/> has created this IRenderResource (or is sharing with the creator).
		/// </para>
		/// </remarks>
		/// <exception cref="ArgumentNullException">
		/// Exception thrown if <paramref name="ctx"/> is null.
		/// </exception>
		/// <exception cref="ArgumentException">
		/// Exception thrown if <paramref name="ctx"/> is not current to the calling thread.
		/// </exception>
		bool Exists(RenderContext ctx);

		#endregion

		#region Resource Management

		/// <summary>
		/// Create this IRenderResource.
		/// </summary>
		/// <param name="ctx">
		/// A <see cref="RenderContext"/> used for creating this object. The object space of this <see cref="RenderContext"/> is used
		/// to generate <see cref="ObjectName"/>, and all contextes sharing lists with this parameter can handle this IRenderResource.
		/// The <see cref="RenderContext"/> shall be current to the calling thread.
		/// </param>
		/// <remarks>
		/// <para>
		/// After a successfull call to Create, <see cref="Exists"/> shall return true.
		/// </para>
		/// </remarks>
		/// <seealso cref="Delete"/>
		void Create(RenderContext ctx);

		/// <summary>
		/// Delete this IRenderResource.
		/// </summary>
		/// <param name="ctx">
		/// A <see cref="RenderContext"/> used for deleting this object. The IRenderResource shall belong to the object space to this
		/// <see cref="RenderContext"/>. The <see cref="RenderContext"/> shall be current to the calling thread.
		/// </param>
		/// <remarks>
		/// <para>
		/// After a successfull call to Create, <see cref="Exists"/> shall return true.
		/// </para>
		/// </remarks>
		/// <seealso cref="Create"/>
		void Delete(RenderContext ctx);

		#endregion

		#region Asynchronous Resource Management

		/// <summary>
		/// Release this IRenderResource.
		/// </summary>
		/// <remarks>
		/// The implementation of this method shall release the graphics resources in a later stage, not the object itself. For more
		/// information see <see cref="RenderGarbageService"/>.
		/// </remarks>
		void Release();

		#endregion
	}
}
